﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace FierceWar
{
	public class MyCamera : FreeCamera
	{
		private const float SPACE_BOUND = 17000.0f;
		private Vector3 INITIAL_POSITION = new Vector3(0.0f, 5500.0f, 5000.0f);

		private Vector3 _translationOnPlane = Vector3.Zero;
		private float _yawChangedAmount = 0.0f;
		private float _pitchChangedAmount = 0.0f;
		private Vector3 _pivotPosition = Vector3.Zero;

		public MyCamera(Vector3 Position, float Yaw, float Pitch,
			GraphicsDevice graphicsDevice)
			: base(Position, Yaw, Pitch, graphicsDevice)
		{ }

		public void Rotate(float pitch)
		{
			float tmpPitch = Pitch + pitch;
			if (tmpPitch > 0.0f)
			{
				_pitchChangedAmount = -Pitch;
				Pitch = 0.0f;
			}
			else if (tmpPitch < -MathHelper.PiOver2)
			{
				_pitchChangedAmount = -MathHelper.PiOver2 - Pitch;
				Pitch = -MathHelper.PiOver2;
			}
			else
			{
				_pitchChangedAmount = pitch;
				Pitch = tmpPitch;
			}
		}

		public override void Rotate(float YawChange, float PitchChange)
		{
			base.Rotate(YawChange, PitchChange);
			_yawChangedAmount = YawChange;
		}

		public void MoveOnPlane(Vector3 translationOnPlane)
		{
			this._translationOnPlane = translationOnPlane;
		}

		public void Reset()
		{
			Position = INITIAL_POSITION;
			Yaw = 0.0f;
			Pitch = -MathHelper.PiOver4;
			_pivotPosition = Vector3.Zero;
		}

		public override void Update()
		{
			// Calculate the rotation matrix
			Matrix rotationXY = Matrix.CreateFromYawPitchRoll(Yaw, Pitch, 0.0f);
			Matrix rotationY = Matrix.CreateRotationY(Yaw);

			// Offset the position when moving.
			translation = Vector3.Transform(translation, rotationXY);
			_translationOnPlane = Vector3.Transform(_translationOnPlane, rotationY);
			Position += translation;
			Position += _translationOnPlane;

			// Update pivot's position when moving and rotating around Y-axis.
			_pivotPosition += _translationOnPlane;
			_pivotPosition.Y = 0.0f;
			if (_yawChangedAmount != 0.0f)
			{
				Vector3 positionProjected = 
					new Vector3(Position.X, 0.0f, Position.Z);
				Vector3 pivotToPositionProjected =
					_pivotPosition - positionProjected;
				Matrix rotationAroundPositionProjected =
					Matrix.CreateTranslation(pivotToPositionProjected) *
					Matrix.CreateRotationY(_yawChangedAmount) *
					Matrix.CreateTranslation(positionProjected);
				_pivotPosition = rotationAroundPositionProjected.Translation;
			}

			// Rotate around a pivot on the ground.
			if (_pitchChangedAmount != 0.0f)
			{
				Vector3 pivotPositionOffset = Position - _pivotPosition;
				Matrix rotationAroundPivotOnGround =
					Matrix.CreateTranslation(pivotPositionOffset) *
					Matrix.CreateFromAxisAngle(Right, _pitchChangedAmount) *
					Matrix.CreateTranslation(_pivotPosition);
				Position = rotationAroundPivotOnGround.Translation;
			}

			/*
			if (Position.X < -SPACE_BOUND)
			{
				Position = new Vector3(-SPACE_BOUND, Position.Y, Position.Z);
			}

			if (Position.X > SPACE_BOUND)
			{
				Position = new Vector3(SPACE_BOUND, Position.Y, Position.Z);
			}

			if (Position.Z < -SPACE_BOUND + 2500.0f)
			{
				Position = new Vector3(Position.X, Position.Y, -SPACE_BOUND + 2500.0f);
			}

			if (Position.Z > SPACE_BOUND + 5000.0f)
			{
				Position = new Vector3(Position.X, Position.Y, SPACE_BOUND + 5000.0f);
			}
			*/
			
			// Reset some properties.
			_yawChangedAmount = 0.0f;
			_pitchChangedAmount = 0.0f;
			translation = Vector3.Zero;
			_translationOnPlane = Vector3.Zero;

			// Calculate the new target
			Vector3 forward = Vector3.Transform(Vector3.Forward, rotationXY);
			Target = Position + forward;

			// Calculate the up vector
			Vector3 up = Vector3.Transform(Vector3.Up, rotationXY);

			// Calculate the view matrix
			View = Matrix.CreateLookAt(Position, Target, up);

			Up = up;
			Right = Vector3.Cross(forward, up);
		}
	}
}
